﻿//========================================================= 
/**@file odbc_extractor.h
 * @brief ODBC简单的封装
 * 
 * @date 2018-08-08   15:34:02
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_ODBC_EXTRACTOR_H_
#define _LIBZHOUYB_ODBC_EXTRACTOR_H_
//--------------------------------------------------------- 
#include <sql.h>
#include <sqlext.h>

#include "../../include/Base.h"

#ifdef _MSC_VER
#   pragma comment(lib, "odbc32.lib")
#endif
//--------------------------------------------------------- 
namespace zhou_yb {
namespace wrapper {
namespace odbc_extractor {
//--------------------------------------------------------- 
/* 类引用声明 */
class sql_dbc;
class sql_stmt;
//--------------------------------------------------------- 
class sql_env
{
public:
    static sql_env create()
    {
        SQLHENV hEnv = SQL_NULL_HENV;
        SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &hEnv);

        sql_env env;
        if(SQL_SUCCEEDED(ret))
        {
            env._env = hEnv;
            ret = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
        }
        return env;
    }
protected:
    shared_obj<SQLHENV> _env;
public:
    sql_env() : _env(SQL_NULL_HENV) {}
    virtual ~sql_env()
    {
        dispose();
    }

    inline operator SQLHENV() const
    {
        return _env;
    }
    inline bool is_valid() const
    {
        return SQL_NULL_HENV != _env;
    }
    void close()
    {
        SQLFreeHandle(SQL_HANDLE_ENV, _env);
        _env = SQL_NULL_HENV;
    }
    void dispose()
    {
        if(_env.ref_count() < 2 && is_valid())
        {
            close();
            return;
        }
        _env.reset() = SQL_NULL_HENV;
    }

    sql_dbc connect(const char* svr, const char* user, const char* pwd);
};
class sql_dbc
{
public:
    friend class sql_env;
protected:
    shared_obj<SQLHDBC> _dbc;
    sql_env _env;
public:
    sql_dbc() : _dbc(SQL_NULL_HDBC), _env() {}
    virtual ~sql_dbc()
    {
        dispose();
    }

    inline operator SQLHDBC() const
    {
        return _dbc;
    }
    inline bool is_valid() const
    {
        return SQL_NULL_HDBC != _dbc;
    }
    void close()
    {
        SQLDisconnect(_dbc);
        SQLFreeHandle(SQL_HANDLE_DBC, _dbc);
        _dbc = SQL_NULL_HDBC;
    }
    void dispose()
    {
        if(_dbc.ref_count() < 2 && is_valid())
        {
            close();
            return;
        }
        _dbc.reset() = SQL_NULL_HDBC;
    }

    sql_stmt create();
};
class sql_stmt
{
public:
    friend class sql_dbc;
protected:
    shared_obj<SQLHSTMT> _stmt;
    sql_dbc _dbc;
public:
    sql_stmt() : _stmt(SQL_NULL_HSTMT), _dbc() {}
    virtual ~sql_stmt()
    {
        dispose();
    }

    inline operator SQLHSTMT() const
    {
        return _stmt;
    }
    inline bool is_valid() const
    {
        return SQL_NULL_HSTMT != _stmt;
    }
    void close()
    {
        SQLFreeHandle(SQL_HANDLE_STMT, _stmt);
        _stmt = SQL_NULL_HSTMT;
    }
    void dispose()
    {
        if(_stmt.ref_count() < 2 && is_valid())
        {
            close();
            return;
        }
        _stmt.reset() = SQL_NULL_HSTMT;
    }

    bool prepare(const char* sql)
    {
        CharConverter cvt;
        const char_t* pSql = cvt.to_char_t(sql);
        SQLRETURN ret = SQLPrepare(_stmt, ctype_cast(SQLTCHAR*)pSql, SQL_NTS);
        return SQL_SUCCEEDED(ret);
    }
    bool exec_direct(const char* direct)
    {
        CharConverter cvt;
        const char_t* pDirect = cvt.to_char_t(direct);
        SQLRETURN ret = SQLExecDirect(_stmt, ctype_cast(SQLTCHAR*)pDirect, SQL_NTS);
        return SQL_SUCCEEDED(ret);
    }
    bool bind()
    {
        return true;
    }
    bool execute()
    {
        SQLRETURN ret = SQLExecute(_stmt);
        return SQL_SUCCEEDED(ret);
    }
    size_t row_count()
    {
        SQLSMALLINT count = 0;
        SQLNumResultCols(_stmt, &count);
        return static_cast<size_t>(count);
    }
    bool fetch()
    {
        return SQL_SUCCEEDED(SQLFetch(_stmt));
    }
    bool get_data(size_t col, SQLSMALLINT type, void* data, SQLLEN* len = NULL)
    {
        SQLLEN colLen = 0;
        SQLRETURN ret = SQLColAttribute(_stmt, 1, SQL_DESC_LENGTH, NULL, 0, 0, &colLen);
        if(!SQL_SUCCEEDED(ret))
            return false;
        ret = SQLGetData(_stmt, 1, type, ctype_cast(SQLPOINTER)data, colLen, len);
        return SQL_SUCCEEDED(ret);
    }
};
//--------------------------------------------------------- 
} // namespace odbc_extractor 
} // namespace wrapper
} // namespace zhou_yb 
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_ODBC_EXTRACTOR_H_
//========================================================= 